package com.klod.news.data


import com.klod.news.base.BaseResponse
import com.klod.news.config.AppConfig
import com.klod.news.ext.logE

import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.android.Android
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.ClientRequestException
import io.ktor.client.plugins.DefaultRequest
import io.ktor.client.plugins.HttpSend
import io.ktor.client.plugins.RedirectResponseException
import io.ktor.client.plugins.ServerResponseException
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.plugins.logging.LogLevel
import io.ktor.client.plugins.logging.Logging
import io.ktor.client.request.get
import io.ktor.client.request.header
import io.ktor.client.request.parameter
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.client.statement.HttpResponse
import io.ktor.client.utils.EmptyContent.contentType
import io.ktor.http.ContentType
import io.ktor.http.contentType
import io.ktor.http.isSuccess
import io.ktor.serialization.gson.gson
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flow
import java.net.ConnectException
import java.net.UnknownHostException
import kotlin.code
import kotlin.text.append


object KtorClient {


    // 设置宽松模式
//    private val gson1 = GsonBuilder().setStrictness(Strictness.LENIENT).create()
    val client = HttpClient(CIO) {
        install(ContentNegotiation) {
//            json(Json {
//                ignoreUnknownKeys = true
//                isLenient = true
//            })
            gson()
        }
        install(DefaultRequest) {
            header("MyCustomHeader", "My-Head")
            header("Authorization", "Bearer your-access-token")

        }

        install(Logging) {
            logger = object : io.ktor.client.plugins.logging.Logger {
                override fun log(message: String) {
                    var m = when{
                        message.startsWith("REQUEST")-> "请求 "
                        message.startsWith("RESPONSE")-> "响应 "
                        else->""
                    }
                    (m + message).logE()
                }
            }
            level = LogLevel.ALL
        }
    }

    inline fun <reified T> requestGet(url: String, map: MutableMap<String, Any>) = flow {
        emit(NetworkResult.Loading())
        try {
            val response: HttpResponse = client.get(url) {
                map.forEach {
                    parameter(it.key, it.value)
                }
            }
            if (response.status.isSuccess()) {

                val result: BaseResponse<T> = response.body()
                if (result.code == 200 || result.code == 0) {
                    try {
                        emit(NetworkResult.Success(result.data))
                    } catch (e: Exception) {
                        emit(NetworkResult.Error(NetworkError.SerializationError()))
                    }

                } else {
                    emit(NetworkResult.Error(NetworkError.HttpError(result.code, result.message)))
                }

            } else {
                emit(
                    NetworkResult.Error(
                        NetworkError.HttpError(
                            response.status.value,
                            response.status.description
                        )
                    )
                )
            }
        } catch (e: RedirectResponseException) {
            emit(
                NetworkResult.Error(
                    NetworkError.HttpError(
                        e.response.status.value,
                        e.response.status.description
                    )
                )
            )
        } catch (e: ClientRequestException) {
            emit(
                NetworkResult.Error(
                    NetworkError.HttpError(
                        e.response.status.value,
                        e.response.status.description
                    )
                )
            )
        } catch (e: ServerResponseException) {
            emit(
                NetworkResult.Error(
                    NetworkError.HttpError(
                        e.response.status.value,
                        e.response.status.description
                    )
                )
            )
        } catch (e: UnknownHostException) {
            emit(NetworkResult.Error(NetworkError.NetworkUnavailable()))
        } catch (e: ConnectException) {
            emit(NetworkResult.Error(NetworkError.ConnectError()))
        } catch (e: Exception) {
            emit(NetworkResult.Error(NetworkError.UnknownError(e.message ?: "Unknown Error")))

        }
    }

    suspend inline fun <reified T> requestGetList(
        url: String,
        map: MutableMap<String, Any>
    ): BaseResponse<T> {
        val response: HttpResponse = client.get(url) {
            map.forEach {
                parameter(it.key, it.value)
            }
        }
        val result: BaseResponse<T> = response.body()
        return result


    }

    inline fun <reified T> requestPost(url: String, data: Any) = flow {
        emit(NetworkResult.Loading())
        try {
            val response: HttpResponse = client.post(url) {
                contentType(ContentType.Application.Json)
                setBody(data)
            }
            if (response.status.isSuccess()) {
                val result: BaseResponse<T> = response.body()
                if (result.code == 200 || result.code == 0) {
                    try {
                        emit(NetworkResult.Success(result.data))
                    } catch (e: Exception) {
                        emit(NetworkResult.Error(NetworkError.SerializationError()))
                    }
                } else {
                    emit(NetworkResult.Error(NetworkError.HttpError(result.code, result.message)))
                }
            } else {
                emit(
                    NetworkResult.Error(
                        NetworkError.HttpError(
                            response.status.value,
                            response.status.description
                        )
                    )
                )
            }
        } catch (e: RedirectResponseException) {
            emit(
                NetworkResult.Error(
                    NetworkError.HttpError(
                        e.response.status.value,
                        e.response.status.description
                    )
                )
            )
        } catch (e: ClientRequestException) {
            emit(
                NetworkResult.Error(
                    NetworkError.HttpError(
                        e.response.status.value,
                        e.response.status.description
                    )
                )
            )
        } catch (e: ServerResponseException) {
            emit(
                NetworkResult.Error(
                    NetworkError.HttpError(
                        e.response.status.value,
                        e.response.status.description
                    )
                )
            )
        } catch (e: UnknownHostException) {
            emit(NetworkResult.Error(NetworkError.NetworkUnavailable()))
        } catch (e: ConnectException) {
            emit(NetworkResult.Error(NetworkError.ConnectError()))
        } catch (e: Exception) {
            emit(NetworkResult.Error(NetworkError.UnknownError(e.message ?: "Unknown Error")))
        }
    }

    inline fun <reified T> requestPostNotBase(url: String, data: Map<String, Any>) = flow {
        emit(NetworkResult.Loading())
        try {
            val response: HttpResponse = client.post(url) {
                contentType(ContentType.Application.Json)
                setBody(data)
            }
            if (response.status.isSuccess()) {
                val result: T = response.body()

                try {
                    emit(NetworkResult.Success(result))
                } catch (e: Exception) {
                    emit(NetworkResult.Error(NetworkError.SerializationError()))
                }

            } else {
                emit(
                    NetworkResult.Error(
                        NetworkError.HttpError(
                            response.status.value,
                            response.status.description
                        )
                    )
                )
            }
        } catch (e: RedirectResponseException) {
            emit(
                NetworkResult.Error(
                    NetworkError.HttpError(
                        e.response.status.value,
                        e.response.status.description
                    )
                )
            )
        } catch (e: ClientRequestException) {
            emit(
                NetworkResult.Error(
                    NetworkError.HttpError(
                        e.response.status.value,
                        e.response.status.description
                    )
                )
            )
        } catch (e: ServerResponseException) {
            emit(
                NetworkResult.Error(
                    NetworkError.HttpError(
                        e.response.status.value,
                        e.response.status.description
                    )
                )
            )
        } catch (e: UnknownHostException) {
            emit(NetworkResult.Error(NetworkError.NetworkUnavailable()))
        } catch (e: ConnectException) {
            emit(NetworkResult.Error(NetworkError.ConnectError()))
        } catch (e: Exception) {
            emit(NetworkResult.Error(NetworkError.UnknownError(e.message ?: "Unknown Error")))
        }
    }
}